{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "C++ 中的引用（`reference`）与指针（`pointer`）\n",
    "\n",
    "| 对比维度           | 引用 `T&`                        | 指针 `T*`                                    |\n",
    "| ------------------ | -------------------------------- | -------------------------------------------- |\n",
    "| 绑定/指向对象      | 必须在定义时绑定到某个对象       | 可以在定义时为空，也可以 senere 指向其他对象 |\n",
    "| 是否可重新绑定     | **不可**，一旦绑定终身不变       | **可以**，随时修改指向                       |\n",
    "| 是否可以为空       | 理论上不支持空引用（标准不允许） | 可以是 `nullptr`（空指针）                   |\n",
    "| 语法使用           | 直接像普通变量一样使用           | 通过 `*` 解引用，`->` 访问成员               |\n",
    "| 所占空间           | 通常与指针同样大小（实现定义）   | 与平台指针大小相同                           |\n",
    "| 多级（指向指针）   | 不支持引用的引用（即 `T& &`）    | 支持多级指针 `T**`                           |\n",
    "| 是否需要显式解引用 | 不需要                           | 需要使用 `*` 解引用或 `->`                   |\n",
    "| 与数组的关系       | 引用数组元素时更直观             | 指针能灵活遍历数组和指针算术                 |\n",
    "| 默认初始化         | 必须在声明时初始化               | 可以不初始化（危险！）或初始化为 `nullptr`   |\n",
    "| 常量性             | 常引用 `const T&` 常用于只读视角 | 指针既可以修饰自己也可以修饰指向对象         |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 引用的特点"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "int x = 10;\n",
    "int& ref = x; // ref 引用 x\n",
    "ref = 20;     // x 变成 20"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 必须初始化，一旦绑定到 `x`，就不能再绑定到其他变量。\n",
    "- 使用上与原变量无异，可视为别名。\n",
    "\n",
    "**常用场景：**\n",
    "\n",
    "- 函数参数：避免复制大型对象，或希望函数修改调用者的变量。\n",
    "- 返回值：返回对象/类的别名，实现链式调用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 指针的特点"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "int x = 10;\n",
    "int* ptr = &x; // ptr 指向 x\n",
    "*ptr = 20;     // x 变成 20\n",
    "\n",
    "int y = 30;\n",
    "ptr = &y;      // ptr 现在改为指向 y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 可以指向不同对象。\n",
    "- 可以为空 `nullptr`，需检查后才能使用。\n",
    "- 可以进行指针算术，例如遍历数组："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "int arr[] = {1, 2, 3};\n",
    "int* p = arr;\n",
    "++p; // 指向 arr[1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**常用场景：**\n",
    "\n",
    "- 动态内存管理（配合 `new/delete` 或智能指针）。\n",
    "- 表示可选、可为空的引用关系。\n",
    "- 底层 API、数组操作、回调等。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 引用 vs 指针：用哪个？\n",
    "\n",
    "- **尽量用引用**：当你确定对象必须存在，函数需要读写或只读，传引用最直观；尤其常引用 `const T&` 可以避免拷贝。\n",
    "- **用指针**：当目标可能为空、需要动态控制指向对象、或必须体现“可无”的语义时。\n",
    "\n",
    "> 比如访问链表节点：`Node* next;` 没有节点时就是 `nullptr`，引用就做不到。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 常见用法对比"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "// 引用传参：必有对象，函数直接操作原对象\n",
    "void increment(int& x) {\n",
    "    ++x;\n",
    "}\n",
    "\n",
    "// 指针传参：允许传入空指针，调用者需检查\n",
    "void increment(int* x) {\n",
    "    if (x) ++(*x);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 与 `const` 搭配\n",
    "\n",
    "- `const T&`：引用只读常量。\n",
    "- `T* const`：指针本身不可改，指向固定。\n",
    "- `const T*`：指向常量，禁止通过指针修改目标。\n",
    "- `const T* const`：指针和指向都不可改。\n",
    "\n",
    "常见模式：`const std::shared_ptr<Foo>&` —— 避免拷贝指针实体，仍能读写指向对象。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 与智能指针配合\n",
    "\n",
    "- 函数参数：常用 `const std::shared_ptr<Foo>&` 或 `std::shared_ptr<Foo>` 按值传递（若需拷贝所有权）。\n",
    "- 若某接口可有可无，可用 `std::shared_ptr<Foo>` 或裸指针 `Foo*` 向上兼容。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 小结\n",
    "\n",
    "- **引用 = 别名**，更安全，不可空，语法直观。你已有一个对象，只想借个“别名”来用，就选它。\n",
    "- **指针 = 地址**，灵活，可空，可重定向，但要小心空指针和内存管理。需要“可能不存在”的语义或操作数组、底层资源时，选它。\n",
    "\n",
    "掌握二者的语义差别，有助于写出意图清晰、安全的 C++ 代码。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
